/******************************************************************************
 * @brief    命令管理器
 * Change Logs:
 * Date           Author         Email                   Notes
 * 2023-06-06      子恒     3393018959@qq.com      Initial version
 *
 * 2023-09-04      子恒     3393018959@qq.com      1、增加内置HELP命令选配
 *                                                 2、增加自定义子串分割符
 *
 * 2023-09-06      子恒     3393018959@qq.com      1、优化b_cmd_t类型为常量
 *                                                 2、优化b_cmd_str_t->*pstr为常量指针
 *
 * 2023-12-01      子恒     3393018959@qq.com       1、优化接口
 *                                                  2、避免使用spritf函数，以便8位机通用
 *
 * 2024-04-09      子恒     3393018959@qq.com       1、简化移植方式<依赖ringbuffer>
 *                                                  2、增加字符串匹配表，用于匹配非命令格式字符串，可裁剪
 ******************************************************************************/


#ifndef __B_CMD_H__
#define __B_CMD_H__

#include "ringbuffer.h"
#include "string.h"
#include "stdint.h"

// 版本信息
#define B_CMD_HELP_PRINT "\r\nWelcome to use b_cmd v1.0.5\r\n"

// 命令回调函数执行成功返回值
#define B_CMD_RET_PASS 0

// 命令回调函数执行失败返回值
#define B_CMD_RET_FAIL !B_CMD_RET_PASS

// 定义命令帧头分割符
#define B_CMD_HEAD_STR "$CFG"

// 使能打印命令子串
#define B_CMD_VAR_PRINT_EN 1

// 使能HELP命令
#define B_CMD_HELP_EN 1

// 接收队列缓存大小
#define B_CMD_RING_MAX 64

// 一行命令缓存大小
#define B_CMD_LINE_CHAR_MAX 64

// 最大命令参数个数
#define B_CMD_ARGS_NUM_MAX 15u

// 执行成功响应输出
#define B_CMD_EXE_SUCESS_STR "CMD PASS!\r\n\r\n"

// 执行失败响应输出
#define B_CMD_EXE_FAIL_STR "CMD FAIL!\r\n\r\n"

// 命令字符串结束分隔符
#define B_CMD_END_STR "\r\n"

// 命令子字符串分隔符
#define B_CMD_SPLIT_STR " "

#if (B_CMD_RING_MAX & (B_CMD_RING_MAX - 1)) != 0
#error "B_CMD_RING_MAX is pow 2"
#endif

/* 输出字符回调函数 */
typedef void b_cmd_out_char_cb_t(const char);

/* 命令执行回调函数 */
// argc：命令字串个数<不包括命令帧头>
// argv: 指针数组，指向分割后的命令字串。例argv[0]指向第一个命令子串
typedef uint8_t b_cmd_cb_t(uint8_t argc, char *argv[]);

/* 命令结构定义 */
typedef struct
{
    char *head_name; /* 命令名 */
    b_cmd_cb_t *cb;  /* 命令执行函数 */
#if (B_CMD_HELP_EN != 0)
    const char *help_str; /* 命令帮助信息 */
#endif
} b_cmd_t;


/* 字符串执行回调函数 */
typedef uint8_t b_str_cb_t(void);

/* 字符串匹配结构定义*/
typedef struct
{
    char *pstr;     /*指向待匹配的字符串*/
    b_str_cb_t *cb; /*回调函数 */
#if (B_CMD_HELP_EN != 0)
    const char *help_str; /*帮助信息 */
#endif
    uint8_t _i;    /*索引*/
    uint8_t _flag; /*默认取值0*/
} b_cmd_str_t;


/* cmd管理器 */
typedef struct
{
    const b_cmd_t *cmds;             /*指向命令表*/
    const b_cmd_str_t *strs;         /*指向字符串表*/
    char line[B_CMD_LINE_CHAR_MAX];  /* 一行字符串存储 */
    b_cmd_out_char_cb_t *pf_outchar; /* 输出字符回调函数 */
} b_cmd_mgr_t;


// 初始化命令管理器
// cmds：命令管理器数组<最后一个成员必须为NULL>，可以为NULL
// strs：特殊格式字符串列表<最后一个成员必须为NULL>，可以为NULL
// cb：打印一个字符<内置响应信息输出，可以为NULL>
extern void cmd_mgr_init(const b_cmd_t *cmds, const b_cmd_str_t *strs, void *putc_cb);

// 主循环调用
extern void b_cmd_task(void);

// put字符到缓冲区，返回B_CMD_RET_PASS代表成功
extern uint8_t cmd_ring_puts(uint8_t *pch,uint8_t len);

// 内置响应信息输出,建议命令相关打印信息使用该函数
extern void b_cmd_put_char(const char ch);
extern void b_cmd_put_str(const char *const str);
#endif
